/* -------------------------------------------------------------------------- */
/*                                 Boolean                                    */
/* -------------------------------------------------------------------------- */

let isDone: boolean = false;

/* -------------------------------------------------------------------------- */
/*                                  Number                                    */
/* -------------------------------------------------------------------------- */

let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
// let big: bigint = 100n; // @target: ES2020

/* -------------------------------------------------------------------------- */
/*                                  String                                    */
/* -------------------------------------------------------------------------- */

let color: string = "blue";
// prettier-ignore
color = 'red';

let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${fullName}.

I'll be ${age + 1} years old next month.`;

/* -------------------------------------------------------------------------- */
/*                                  Array                                     */
/* -------------------------------------------------------------------------- */

let list1: number[] = [1, 2, 3];

let list2: Array<number> = [1, 2, 3];

/* -------------------------------------------------------------------------- */
/*                                    Tuple                                   */
/* -------------------------------------------------------------------------- */

// @errors: 2322
// Declare a tuple type
let x: [string, number];
// Initialize it
x = ["hello", 10]; // OK
// Initialize it incorrectly
// x = [10, "hello"]; // Error
/// ---cut---
// OK
console.log(x[0].substring(1));

// console.log(x[1].substring(1)); // method not exist
// x[3] = "world"; // @errors: 2322
// console.log(x[5].toString());

/* -------------------------------------------------------------------------- */
/*                                    Enum                                    */
/* -------------------------------------------------------------------------- */

enum Color {
  Red,
  Green,
  Blue,
}
let c: Color = Color.Green;

// enum Color {
//   Red = 1,
//   Green = 2,
//   Blue = 4,
// }
// let c: Color = Color.Green;
let colorName: string = Color[2];

// Displays 'Green'
console.log(colorName);

/* -------------------------------------------------------------------------- */
/*                                   Unkonwn                                  */
/* -------------------------------------------------------------------------- */

let notSure: unknown = 4;
notSure = "maybe a string instead";

// OK, definitely a boolean
notSure = false;

// // @errors: 2322 2322 2322
// declare const maybe: unknown;
// // 'maybe' could be a string, object, boolean, undefined, or other types
// const aNumber: number = maybe;

// if (maybe === true) {
//   // TypeScript knows that maybe is a boolean now
//   const aBoolean: boolean = maybe;
//   // So, it cannot be a string
//   const aString: string = maybe;
// }

// if (typeof maybe === "string") {
//   // TypeScript knows that maybe is a string
//   const aString: string = maybe;
//   // So, it cannot be a boolean
//   const aBoolean: boolean = maybe;
// }

/* -------------------------------------------------------------------------- */
/*                                     Any                                    */
/* -------------------------------------------------------------------------- */

declare function getValue(key: string): any;
// OK, return value of 'getValue' is not checked
const str: string = getValue("myString");

let looselyTyped: any = {};
let d = looselyTyped.a.b.c.d;
//  ^?

/* -------------------------------------------------------------------------- */
/*                                      Void                                  */
/* -------------------------------------------------------------------------- */

function warnUser(): void {
  console.log("This is my warning message");
}

// Null and Undefined

// Not much else we can assign to these variables!
let u: undefined = undefined;
let n: null = null;

/* -------------------------------------------------------------------------- */
/*                                    Never                                   */
/* -------------------------------------------------------------------------- */

// Function returning never must not have a reachable end point
function error(message: string): never {
  throw new Error(message);
}

// Inferred return type is never
function fail() {
  return error("Something failed");
}

// Function returning never must not have a reachable end point
function infiniteLoop(): never {
  while (true) {}
}

/* -------------------------------------------------------------------------- */
/*                                   Object                                   */
/* -------------------------------------------------------------------------- */

// @errors: 2345
declare function create(o: object | null): void;

// OK
create({ prop: 0 });
create(null);

// create(42);
// create("string");
// create(false);
// create(undefined);


/* -------------------------------------------------------------------------- */
/*                               Type assertions                              */
/* -------------------------------------------------------------------------- */

let someValue: unknown = "this is a string";

let strLength: number = (someValue as string).length;

// let someValue: unknown = "this is a string";

// let strLength: number = (<string>someValue).length;